#include <iostream>

#include <log4cxx/logger.h>
#include <log4cxx/xml/domconfigurator.h>

#include "MysqlConnPool.h"
#include "sfs_common.h"
#include "SFSDBOperation.h"

#define MYSQL_CONN_POOL_NUM 5
#define SFS_DB_NAME "SFS"
#define TEST_DATA_NODE_CONFIG_IP "192.168.1.1"
#define TEST_DATA_NODE_CONFIG_PORT 7000
#define TEST_DATA_NODE_CONFIG_NAMESPACE_ID 0
#define TEST_NAMESPACE_CONFIG_NAMESPACE_ID 0 
#define TEST_NAMESPACE_CONFIG_NAMESPACE_WEIGHT 10
#define TEST_FILE_METADATA_FILE_PATH "/1/10/10/abc"
#define TEST_FILE_METADATA_FILE_SIZE 100
#define TEST_FILE_METADATA_FILE_VERSION 1
#define TEST_FILE_METADATA_NAMESPACE_ID 0 
#define LOG_CONF_FILE "./log.xml"


using std::cout;
using std::endl;

int show_usage(int argc, char * argv[]) {
		cout << "ussage:" << argv[0] << " mysqld_host mysqld_port mysqld_user mysqld_passwd" << endl;
		return 1;
}

int test_sfs_db_op(int argc, char * argv[]) {
		log4cxx::xml::DOMConfigurator::configure(LOG_CONF_FILE);
		int res = mysql_library_init(-1, NULL, NULL);
		if (0 != res) { cout << "mysql library init fail, res:" << res << endl; return -1; }
		if (5 != argc) { show_usage(argc, argv); return -2; }
		string mysqld_host = argv[1];
		string mysqld_port = argv[2];
		string mysqld_user = argv[3];
		string mysqld_passwd = argv[4];

		MysqlConnPool conn_pool;
		res = conn_pool.init(MYSQL_CONN_POOL_NUM, mysqld_host.c_str(), atoi(mysqld_port.c_str()), SFS_DB_NAME, \
						mysqld_user.c_str(),  mysqld_passwd.c_str());
		if (res < 0) return -3;
		MYSQL_CONN * pconn = conn_pool.acquire_conn();
		if (NULL == pconn) { cout << "can not acquire mysql conn from pool" << endl; return -4; }
		/*----------------test add data node config begin----------------*/
		SFSDBOperation sfs_db_op;
		SFS_DATA_NODE_CONFIG data_node_config;
		data_node_config.data_node_ip = TEST_DATA_NODE_CONFIG_IP;
		data_node_config.data_node_port = TEST_DATA_NODE_CONFIG_PORT;
		data_node_config.data_node_namespace_id = TEST_DATA_NODE_CONFIG_NAMESPACE_ID;
		res = sfs_db_op.add_data_node_config(pconn->mysql, data_node_config);
		if (res < 0) cout << "add data node config error, res:" << res << endl;
		else cout << "add data node config ok, ip:" << data_node_config.data_node_ip << ", port:" << \
				data_node_config.data_node_port << ", namespace_id:" << data_node_config.data_node_namespace_id << endl;
		/*----------------test add data node config end----------------*/
		/*----------------test get data node config by ip and port begin----------------*/
		list<SFS_DATA_NODE_CONFIG> l_data_node_config;
		res = sfs_db_op.get_data_node_config_by_ip_and_port(pconn->mysql, l_data_node_config, TEST_DATA_NODE_CONFIG_IP, \
						TEST_DATA_NODE_CONFIG_PORT);
		if (res < 0) {
				cout << "get data node config by ip and port error, res:" << res << endl;
				return -6;
		}
		struct tm ttm;
		char t[1024];
		for (list<SFS_DATA_NODE_CONFIG>::const_iterator iter = l_data_node_config.begin(); \
						l_data_node_config.end() != iter; iter++) {
				localtime_r(&iter->create_time, &ttm);
				strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", &ttm);
				cout << "get data node config, ip:" << iter->data_node_ip << ", port:" << iter->data_node_port << \
						", namespace_id:" <<  iter->data_node_namespace_id << ", create_time:" << t << endl;
		}
		/*----------------test get data node config by ip and port end----------------*/
		/*----------------test get all data node config begin----------------*/
		list<SFS_DATA_NODE_CONFIG> l_all_data_node_config;
		res = sfs_db_op.get_all_data_node_config(pconn->mysql, l_all_data_node_config);
		if (res < 0) {
				cout << "get all data node config error, res:" << res << endl;
				return -6;
		}
		for (list<SFS_DATA_NODE_CONFIG>::const_iterator iter = l_all_data_node_config.begin(); \
						l_all_data_node_config.end() != iter; iter++) {
				localtime_r(&iter->create_time, &ttm);
				strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", &ttm);
				cout << "get all data node config ok, ip:" << iter->data_node_ip << ", port:" << iter->data_node_port << \
						", namespace_id:" <<  iter->data_node_namespace_id << ", create_time:" << t << endl;
		}
		/*----------------test get all data node config end----------------*/
		/*----------------test get data node config by namespace id begin----------------*/
		list<SFS_DATA_NODE_CONFIG> l_data_node_config_n;
		res = sfs_db_op.get_data_node_config_by_namespace_id(pconn->mysql, l_data_node_config_n, \
						TEST_DATA_NODE_CONFIG_NAMESPACE_ID);
		if (res < 0) {
				cout << "get data node config by namespace_id, res:" << res << endl;
				return -6;
		}
		for (list<SFS_DATA_NODE_CONFIG>::const_iterator iter = l_data_node_config_n.begin(); \
						l_data_node_config_n.end() != iter; iter++) {
				localtime_r(&iter->create_time, &ttm);
				strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", &ttm);
				cout << "get data node config by namespace_id, ip:" << iter->data_node_ip << ", port:" << \
						iter->data_node_port << \
						", namespace_id:" <<  iter->data_node_namespace_id << ", create_time:" << t << endl;
		}
		/*----------------test get data node config by namespace id end----------------*/
		/*----------------test del data node config begin----------------*/
		res = sfs_db_op.del_data_node_config(pconn->mysql, TEST_DATA_NODE_CONFIG_IP, TEST_DATA_NODE_CONFIG_PORT);
		if (res < 0) {
				cout << "del data node config error, res:" << res << endl;
				return -6;
		}
		else cout << "del data node config ok, ip:" << TEST_DATA_NODE_CONFIG_IP << ". port:" << \
				TEST_DATA_NODE_CONFIG_PORT << endl;
		/*----------------test del data node config end----------------*/
		/*----------------test add namespace config begin----------------*/
		SFS_NAMESPACE_CONFIG namespace_config;
		namespace_config.namespace_id = TEST_NAMESPACE_CONFIG_NAMESPACE_ID;
		namespace_config.namespace_weight = TEST_NAMESPACE_CONFIG_NAMESPACE_WEIGHT;
		res = sfs_db_op.add_namespace_config(pconn->mysql, namespace_config);
		if (res < 0) cout << "add namespace config error, res:" << res << endl;
		else cout << "add namespace config ok, namespace id:" << namespace_config.namespace_id << ", namespace weight:" << \
				namespace_config.namespace_weight << endl;
		/*----------------test add namespace config end----------------*/
		/*----------------test get namespace config----------------*/
		SFS_NAMESPACE_CONFIG namespace_config_t;
		res = sfs_db_op.get_namespace_config(pconn->mysql, namespace_config_t, TEST_NAMESPACE_CONFIG_NAMESPACE_ID);
		if (res < 0) {
				cout << "get namespace config port error, res:" << res << endl;
				return -6;
		}
		localtime_r(&(namespace_config_t.create_time), &ttm);
		strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", &ttm);
		cout << "get namespace config, namespace_id:" << namespace_config_t.namespace_id << ", weight:" << \
				namespace_config_t.namespace_weight<< ", create_time:" << t << endl;
		/*----------------test get namespace config end----------------*/
		/*----------------test get all namespace config----------------*/
		list<SFS_NAMESPACE_CONFIG> l_namespace_config;
		res = sfs_db_op.get_all_namespace_config(pconn->mysql, l_namespace_config);
		if (res < 0) {
				cout << "get all namespace config port error, res:" << res << endl;
				return -6;
		}
		for (list<SFS_NAMESPACE_CONFIG>::const_iterator iter = l_namespace_config.begin(); \
						l_namespace_config.end() != iter; iter++) {
				localtime_r(&(iter->create_time), &ttm);
				strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", &ttm);
				cout << "get all namespace config ok, namespace_id:" << iter->namespace_id << ", weight:" << \
						iter->namespace_weight << ", create_time:" << t << endl;
		}
		/*----------------test get all namespace config end----------------*/
		/*----------------test mod namespace config----------------*/
		SFS_NAMESPACE_CONFIG namespace_config_m;
		namespace_config_m.namespace_weight = 20;
		set<string> mod_fields;
		mod_fields.insert("NAMESPACE_WEIGHT");
		res = sfs_db_op.mod_namespace_config(pconn->mysql, namespace_config_m, mod_fields, \
						TEST_NAMESPACE_CONFIG_NAMESPACE_ID);
		if (res < 0) {
				cout << "mod namespace config error, res:" << res << endl;
				return -6;
		}
		else cout << "mod namespace config ok" << endl;
		/*----------------test mod namespace config end----------------*/
		/*----------------test del namespace config begin----------------*/
		res = sfs_db_op.del_namespace_config(pconn->mysql, TEST_NAMESPACE_CONFIG_NAMESPACE_ID);
		if (res < 0) {
				cout << "del namespace config error, res:" << res << endl;
				return -6;
		}
		else cout << "del namespace config ok, namespace_id:" << TEST_NAMESPACE_CONFIG_NAMESPACE_ID << endl; 
		/*----------------test del namespace config end----------------*/
		/*----------------test add file meta data begin----------------*/
		SFS_FILE_METADATA metadata;
		metadata.file_path = TEST_FILE_METADATA_FILE_PATH;
		metadata.file_size = TEST_FILE_METADATA_FILE_SIZE;
		metadata.file_version = TEST_FILE_METADATA_FILE_VERSION;
		res = sfs_db_op.add_file_metadata(pconn->mysql, metadata, TEST_FILE_METADATA_NAMESPACE_ID);
		if (res < 0) cout << "add file meta data error, res:" << res << endl;
		else cout << "add file meta data ok, namespace id:" << TEST_FILE_METADATA_NAMESPACE_ID << ", file_path:" << \
				TEST_FILE_METADATA_FILE_PATH << endl;
		/*----------------test add file meta data end----------------*/
		/*----------------test lock file begin----------------*/
		res = sfs_db_op.lock_file(pconn->mysql, TEST_FILE_METADATA_NAMESPACE_ID, TEST_FILE_METADATA_FILE_PATH);
		if (res < 0) cout << "lock file error, res:" << res << endl;
		else cout << "lock file ok, namespace id:" << TEST_FILE_METADATA_NAMESPACE_ID << ", file_path:" << \
				TEST_FILE_METADATA_FILE_PATH << endl;
		/*----------------test lock file meta data end----------------*/
		/*----------------test unlock file begin----------------*/
		res = sfs_db_op.unlock_file(pconn->mysql, TEST_FILE_METADATA_NAMESPACE_ID, TEST_FILE_METADATA_FILE_PATH);
		if (res < 0) cout << "unlock file error, res:" << res << endl;
		else cout << "unlock file ok, namespace id:" << TEST_FILE_METADATA_NAMESPACE_ID << ", file_path:" << \
				TEST_FILE_METADATA_FILE_PATH << endl;
		/*----------------test unlock file meta data end----------------*/
		/*----------------test get file meta data config----------------*/
		SFS_FILE_METADATA metadata_n;
		char str_lock_time[1024];
		res = sfs_db_op.get_file_metadata(pconn->mysql, metadata_n, TEST_FILE_METADATA_NAMESPACE_ID, \
						TEST_FILE_METADATA_FILE_PATH);
		if (res < 0) {
				cout << "get file metadata error, res:" << res << endl;
				return -6;
		}
		localtime_r(&(metadata_n.create_time), &ttm);
		strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", &ttm);
		if (metadata_n.lock_time == (time_t)-1) {
				snprintf(str_lock_time, sizeof(str_lock_time),  "NULL");
		}
		else {
				localtime_r(&(metadata_n.lock_time), &ttm);
				strftime(str_lock_time, sizeof(str_lock_time), "%Y-%m-%d %H:%M:%S", &ttm);
		}
		cout << "get file metadata, namespace_id:" << TEST_FILE_METADATA_NAMESPACE_ID << ", file_path:" << \
				metadata_n.file_path << ", create_time:" << t << ", file_size:" << metadata_n.file_size << \
				", file_version:" << metadata_n.file_version << ", lock_flag:" << metadata_n.lock_flag << \
				", lock_time:" << str_lock_time << endl;
		/*----------------test get file meta data end----------------*/
		/*----------------test mod file meta data begin----------------*/
		SFS_FILE_METADATA metadata_m;
		metadata_m.file_path = TEST_FILE_METADATA_FILE_PATH;
		//metadata_m.file_size = 300;
		metadata_m.file_version = 4;
		set<string> file_metadata_mod_fields;
		//file_metadata_mod_fields.insert("FILE_SIZE");
		file_metadata_mod_fields.insert("FILE_VERSION");
		res = sfs_db_op.mod_file_metadata(pconn->mysql, metadata_m, file_metadata_mod_fields, \
						TEST_FILE_METADATA_NAMESPACE_ID, \
						TEST_FILE_METADATA_FILE_PATH);
		if (res < 0) cout << "mod file meta data error, res:" << res << endl;
		else cout << "mod file meta data ok" << endl;
		/*----------------test mod file meta data end----------------*/
		/*----------------test del file meta data begin----------------*/
		res = sfs_db_op.del_file_metadata(pconn->mysql, TEST_FILE_METADATA_NAMESPACE_ID, \
						TEST_FILE_METADATA_FILE_PATH);
		if (res < 0) cout << "del file meta data error, res:" << res << endl;
		else cout << "del file meta data ok" << endl;
		/*----------------test del file meta data end----------------*/
	





		conn_pool.release_conn(pconn);
		return 1;
}
int main(int argc, char * argv[]) {
		test_sfs_db_op(argc, argv);
		return 1;
}
